//
// Created by denglibin on 19-10-21.
//
/**
 *父子进程发送信号 SIGUSER1 SIGUSER2
 **/

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<sys/wait.h>

int num = 0;
pid_t pid;
/**
 * 父进程SIGUSER1信号 处理函数
 * @param signo
 */
static void p_handle(int signo){
    if(signo == SIGUSR1){
        printf("p:%d\n", num); // 数数
        num += 2;
        sleep(1);
        //给子进程发SIGUSER2信号
        kill(pid, SIGUSR2);
    }
}
/**
 * 子进程SIGUSER2信号 处理函数
 * @param signo
 */
static void c_handle(int signo){
    if(signo == SIGUSR2){
        printf("c:%d\n", num);
        num += 2;
        sleep(1);
        // 给父进程发SIGUSER1信号
        kill(getppid(), SIGUSR1);
    }
}

/**
 * 父子进程交替数数
 */
static void count_num(){
    pid = fork();
    if(pid == -1){
        perror("fork");
        exit(-1);
    }
    if(pid == 0){ //子进程
        num = 1;
        // 设置信号处理函数
        struct sigaction new_act, old_act;
        new_act.sa_handler = c_handle; //sa_handler此参数和signal()的参数handler相同，代表新的信号处理函数
        sigemptyset(& new_act.sa_mask); // sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置
        new_act.sa_flags = 0; // sa_flags 用来设置信号处理的其他相关操作，下列的数值可用。
        // SA_RESETHAND：当调用信号处理函数时，将信号的处理函数重置为缺省值SIG_DFL
        //SA_RESTART：如果信号中断了进程的某个系统调用，则系统自动启动该系统调用
        //SA_NODEFER ：一般情况下， 当信号处理函数运行时，内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记， 那么在该信号处理函数运行时，内核将不会阻塞该信号

        sigaction(SIGUSR2,&new_act,&old_act);//原来的备份到old_act里面

        sleep(1);// 停一下 等待父进程注册信号处理函数

        //给父进程发SIGUSER1信号
        kill(getppid(), SIGUSR1);

    }else{ // 父进程 pid=子进程id
        // 设置信号处理函数
        struct sigaction new_act, old_act;
        new_act.sa_handler = p_handle; //sa_handler此参数和signal()的参数handler相同，代表新的信号处理函数
        sigemptyset(& new_act.sa_mask); // sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置
        new_act.sa_flags = 0; // sa_flags 用来设置信号处理的其他相关操作，下列的数值可用。
        // SA_RESETHAND：当调用信号处理函数时，将信号的处理函数重置为缺省值SIG_DFL
        //SA_RESTART：如果信号中断了进程的某个系统调用，则系统自动启动该系统调用
        //SA_NODEFER ：一般情况下， 当信号处理函数运行时，内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记， 那么在该信号处理函数运行时，内核将不会阻塞该信号

        sigaction(SIGUSR1,&new_act,&old_act);//原来的备份到old_act里面

    }
}

static int main_(){
    count_num();
    while (1){ // 阻止进程结束
        sleep(2);
    }
    return 0;
}
